-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[web_request] add handling of client_max_size in request body #1414
Conversation
3a56b4e
to
0da4166
Compare
* default limit set to value same as in nginx 1mb; * if client tries to upload body that exceeds this limit it will get 413 HTTP Error; * limit can be updated by massing client_max_size argument to Application object
0da4166
to
b498200
Compare
Codecov Report
@@ Coverage Diff @@
## master #1414 +/- ##
==========================================
+ Coverage 96.61% 96.61% +<.01%
==========================================
Files 30 30
Lines 7293 7298 +5
Branches 1268 1269 +1
==========================================
+ Hits 7046 7051 +5
Misses 149 149
Partials 98 98
Continue to review full report at Codecov.
|
I stumbled on two issues here:
I guess code-cow failing because of missing test for 2. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At first thank you for PR very much.
It worth to be included after some corrections.
Actually aiohttp.errors
is for internal and client use only .
I'd hope to get rid of it at all sometimes -- HttpProcessingError
and family is really confusing.
Server side should use aiohttp.web_exceptions
but end user code should never import it directly: from aiohttp.web_exceptions import HTTPMethodNotAllowed
is ok for aiohttp itself but outer code should do from aiohttp.web import HTTPMethodNotAllowed
.
Server code should catch aiohttp.web_exceptions
but all other exceptions must raise 500 (it's done by server.py
now`).
web_server.py
API is unstable. It was not released yet.
The purpose of the API is introducing much more user friendly way for working with HTTP low-level server (operate with handy Request/Response classes but don't relay on web.Application
, routes etc).
aiohttp/errors.py
Outdated
@@ -122,6 +122,11 @@ class HttpBadRequest(BadHttpMessage): | |||
message = 'Bad Request' | |||
|
|||
|
|||
class HttpRequestEntityTooLarge(HttpProcessingError): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please drop it. The class what you need is already exists and called aiohttp.web.HTTPRequestEntityTooLarge
.
aiohttp/web.py
Outdated
@@ -32,7 +32,8 @@ class Application(MutableMapping): | |||
|
|||
def __init__(self, *, logger=web_logger, loop=None, | |||
router=None, | |||
middlewares=(), debug=...): | |||
middlewares=(), debug=..., | |||
client_max_size=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just use 1MB (1024*1024) as default value.
aiohttp/web_reqrep.py
Outdated
@@ -49,10 +50,13 @@ class BaseRequest(collections.MutableMapping, HeadersMixin): | |||
|
|||
POST_METHODS = {hdrs.METH_PATCH, hdrs.METH_POST, hdrs.METH_PUT, | |||
hdrs.METH_TRACE, hdrs.METH_DELETE} | |||
# Maximum allowed size of request body. | |||
_CLIENT_MAX_SIZE = 1024**2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drop it. The value should be either passed by caller or None
if caller don't care.
No default for it please.
aiohttp/web_reqrep.py
Outdated
if client_max_size: | ||
max_size = client_max_size | ||
else: | ||
max_size = self._CLIENT_MAX_SIZE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
max_size
could be None
if user operates with low-level API (without web.Application
, routers, signals, middlewares and other related stuffs).
aiohttp/web_reqrep.py
Outdated
@@ -363,6 +372,8 @@ def read(self): | |||
while True: | |||
chunk = yield from self._payload.readany() | |||
body.extend(chunk) | |||
if len(body) >= self._client_max_size: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_client_max_size
could be None
aiohttp/web_reqrep.py
Outdated
@@ -363,6 +372,8 @@ def read(self): | |||
while True: | |||
chunk = yield from self._payload.readany() | |||
body.extend(chunk) | |||
if len(body) >= self._client_max_size: | |||
raise HttpRequestEntityTooLarge() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this particular case from .web_exceptions import HTTPRequestEntityTooLarge
is allowed evil.
Yes, I know the import from function has ugly adore.
But I'm ok with this for the case.
aiohttp/web_server.py
Outdated
@@ -53,17 +54,21 @@ def handle_request(self, message, payload): | |||
|
|||
request = self._request_factory(message, payload, self) | |||
self._request = request | |||
resp = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's a bug. Thank you for finding.
aiohttp/web_server.py
Outdated
|
||
try: | ||
try: | ||
resp = yield from self._handler(request) | ||
except HTTPException as exc: | ||
resp = exc | ||
except HttpProcessingError as exc: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All exceptions not derived from HttpProcessingError
should raise 500 Internal Server Errror
(now it's done by server.py
code).
aiohttp/web_server.py
Outdated
|
||
resp_msg = yield from resp.prepare(request) | ||
yield from resp.write_eof() | ||
finally: | ||
resp._task = None | ||
if hasattr(resp, "_task"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you'll use web_exceptions
this code is not needed.
@pawelmhm are you still interested in working on this PR? |
75f87f5
to
be930a4
Compare
Cool, thanks |
* use web_exceptions.HTTPRequestEntityTooLarge instead of same exceptions from errors * allow limit to be None, if limit is None dont perform this check
if self._client_max_size \ | ||
and len(body) >= self._client_max_size: | ||
# local import to avoid circular imports | ||
from aiohttp import web_exceptions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try to import aiohttp.web
. All web exceptions are available i that namedspace
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah I see you merged that, I can check if import of aiohttp.web works, should I open new PR with that + doc updates, adding myself to contributors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed import and added you to contributors already. thanks
thanks |
What do these changes do?
Adding size limits to request body so that malicious client can't cause trouble by trying to upload request with extremely big body.
Are there changes in behavior for the user?
Yes, too big uploads will raise HTTP 413 error.
Related issue number
#1133
Checklist
CONTRIBUTORS.txt
CHANGES.rst
#issue_number
format at the end of changelog message. Use Pull Request number if there are no issues for PR or PR covers the issue only partially.